import logging
import socket
import subprocess
import time
from _socket import timeout

import paramiko
from PyQt5.QtCore import QThread, pyqtSignal, QRunnable, QObject, QThreadPool
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
from paramiko.channel import Channel
from paramiko.client import SSHClient
from paramiko.ssh_exception import AuthenticationException, SSHException

from modules.config import config_path
from modules.desktop_entrys import ssh_add_link, network_share_for_teacher, network_share, veyon_link, smb_conf
from modules.hosts import Host, Hosts
from modules.system import run_command_in_xterm, run_command_in_konsole, user, run_command_by_root, this_host, \
    run_command, get_mac_address, test_ssh, test_ping, check_student_on_host


class PingTest(QThread):
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal()

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        # self.hosts = None
        self.host_list = []

    def run(self):
        cnt = 0
        self.progress_signal.emit("Начало проверки ping\n")
        for host in self.host_list:
            if test_ping(host.hostname):
                logging.info(f"{host.hostname}: проверка ping успешно")
                self.progress_signal.emit(
                    f"{host.name}: проверка ping успешно"
                )
                cnt += 1
            else:
                logging.info(f"{host.hostname}: недоступен")
                self.progress_signal.emit(
                    f"{host.name}: недоступен"
                )
        self.progress_signal.emit(f'\nЗавершение проверки ping.\nДоступно компьютеров: {cnt}')


class SSHRootSetup(QThread):
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal()

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.host_list = []
        # self.root_pass = ""

    def run(self):
        self.progress_signal.emit("Начало настройки SSH")
        self.setup_ssh()

    def ping(self):
        """
        Подключение к хостам и проверка ping
        :return: список хостов в случае успеха
        """
        hosts = self.host_list
        if hosts:
            self.progress_signal.emit("\nСписок устройств найден, выполняю ping всех устройств:")
            errors = 0
            list_of_hosts = []
            for host in hosts:
                result = subprocess.run(['ping', '-c1', host.hostname], stdout=subprocess.PIPE)
                if result.returncode == 0:
                    self.progress_signal.emit(f"ping: {host.hostname}: Успешное соединение")
                    logging.info(f"ping: {host.hostname}: Успешное соединение {result=} {result.returncode=}")
                    list_of_hosts.append(host.hostname)
                elif result.returncode == 2:
                    logging.info(f"ping: {host.hostname}: {result=} {result.returncode=}")
                    self.progress_signal.emit(f"ping: {host.hostname}: Устройство не найдено")
                    errors += 1
                else:
                    self.progress_signal.emit(f"ping: {host.hostname}: неизвестная ошибка")
                    logging.info(host.hostname + f" неизвестная ошибка {result=} {result.returncode=}")
                    errors += 1
            if errors > 0:
                self.progress_signal.emit("Некоторые компьютеры найти не удалось.")
            return list_of_hosts
        else:
            self.progress_signal.emit(
                '\nЗаполните список устройств: '
                'перечислите в нём имена компьютеров и запустите скрипт повторно.\n\n'
                '    ВАЖНО!\n\nДля М ОС имя компьютера должно оканчиваться на .local\n'
            )
            return []

    def setup_ssh(self):
        """
        Создание ключей ssh
        Копирование ключей на хосты для пользователя teacher
        Подключение к хостам под пользователем teacher и копирование ключей пользователю root
        """
        list_of_hosts = self.ping()
        if list_of_hosts:
            logging.info(f"Начало создания ключа")
            self.progress_signal.emit(f"\nСоздание ключа ssh")
            run_command_in_xterm(f"ssh-keygen -t ed25519 -q -P '' -f /home/{user}/.ssh/id_ed25519")
            logging.info(f"Ключ создан")
            self.progress_signal.emit(f"\nКлюч ssh создан")
            time.sleep(1)
            run_command(f'mkdir -p /home/{user}/.config/autostart')
            with open(f'/home/{user}/.config/autostart/ssh-add.desktop', 'w') as file_link:
                file_link.write(ssh_add_link)
            logging.info(f"Ярлык в автозапуск ssh-add создан")
            self.progress_signal.emit(f"Ярлык в автозапуск ssh-add создан")
            logging.info(f"Начало копирования ключей")
            self.progress_signal.emit('\nКопирую ключ на все доступные компьютеры:')
            run_command(f"ssh-add")
            cnt = 0
            for host in self.host_list:
                if host.hostname in list_of_hosts:
                    logging.info(f"Копирование открытого ключа")
                    run_command_in_xterm(
                        f"sshpass -p {host.admin_pass} ssh-copy-id {host.admin_login}@{host.hostname}"
                    )
                    cnt += 1
            logging.info(f"Ключи скопированы на {cnt} компьютеров")
            self.progress_signal.emit("Настройка ssh для пользователя из wheel на всех доступных устройствах")
            successful_hostnames = []
            cnt = 0
            for host in self.host_list:
                hostname = host.hostname.strip()
                if hostname in list_of_hosts:
                    self.progress_signal.emit(f"Попытка подключения к {hostname}")
                    logging.info(f"Попытка подключения к {hostname}")
                    try:
                        result = run_command(f'ssh {host.admin_login}@{host.hostname} ls ~/.ssh')
                        if 'authorized_keys' not in result:
                            self.progress_signal.emit(f"Не найдены ключи на {hostname}")
                            logging.info(f"Не найдены ключи на {hostname}")
                            continue
                        result = self.ssh_copy_to_root(host)
                        if "ssh-ed" not in result:
                            self.progress_signal.emit(f"Пароль root неверный для {hostname}")
                            logging.info(f"Пароль root неверный для {hostname}")
                        else:
                            successful_hostnames.append(host.name)
                            self.progress_signal.emit(f"На {hostname} ssh для root настроен успешно")
                            logging.info(f"На {hostname} ssh для root настроен успешно")
                            cnt += 1
                    except Exception as e:
                        logging.info(f"{e}  ---  Не удалось подключиться к {hostname}")
                        self.progress_signal.emit(f"Не удалось подключиться к {hostname}")
                        continue
            for name in successful_hostnames:
                self.hosts.set_true_setup(name)
            self.progress_signal.emit(f'\nНастройка SSH завершена.\nНастроено компьютеров: {cnt}')

    def ssh_copy_to_root(self, host):
        """
        Копирование ключей ssh от teacher в root
        :param host: объект класса Host
        :return: вывод результата от терминала
        """
        logging.info("Начало копирования ключей ssh to root")
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.load_system_host_keys()
        try:
            ssh.connect(hostname=host.hostname, port=22, timeout=5, username=host.admin_login,
                        password=host.admin_pass, allow_agent=False, look_for_keys=False)
            logging.info(f"Подключено по ssh@{host.admin_login} к {host.hostname}")
            channel: Channel = ssh.invoke_shell()
            channel_data = str()
            time.sleep(0.5)
            channel.send(f"sudo mkdir -p /root/.ssh && "
                         f"cat /home/{host.admin_login}/.ssh/authorized_keys | sudo tee /root/.ssh/authorized_keys\n")
            time.sleep(0.5)
            channel.send(f"{host.admin_pass}\n")
            time.sleep(0.5)
            channel_data += f"{str(channel.recv(99999).decode('utf-8'))}\n"
            channel.close()
            ssh.close()
            logging.info(f"Результат работы paramiko на {host.hostname}: {channel_data}")
            return channel_data
        except AuthenticationException as e:
            self.progress_signal.emit(f'Неправильно настроены ключи авторизации для {host.admin_login}@{host.hostname}')
            logging.info(f"{e} Не удалось подключиться к ssh@{host.admin_login} к {host.hostname}")
        except (timeout, SSHException) as e:
            self.progress_signal.emit(f'Не удалось подключиться к ssh {host.admin_login}@{host.hostname}')
            logging.info(f"{e} Не удалось подключиться к ssh@{host.admin_login} к {host.hostname}")
        except Exception as e:
            self.progress_signal.emit(f'Не удалось подключиться к ssh {host.admin_login}@{host.hostname}')
            logging.info(f"{e} Не удалось подключиться к ssh {host.admin_login}@{host.hostname}")
        finally:
            ssh.close()


class NetworkFolderSetup(QThread):
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal()

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        # self.hosts = None
        self.host_list = []

    def run(self):
        self.network_folders()

    def network_folders(self):
        """
        Создание сетевой папки и копирование ярлыка по ssh на хосты
        """
        logging.info("Создание сетевой папки")
        self.progress_signal.emit("Начало настройки сетевых папок")
        hosts_count = len(self.host_list)
        success_count = 0
        self.progress_signal.emit(
            'Создание сетевой папки share (/home/share) и отправка ссылки на компьютеры учеников'
        )
        if smb_conf not in run_command("cat /etc/samba/smb.conf"):
            logging.info("Установка samba с конфигом")
            run_command_by_root(
                f'dnf makecache && '
                f'dnf in -y samba && '
                f'mkdir -p /home/share && '
                f'chmod 777 /home/share && '
                f'echo -e \\"{smb_conf}\\" >> /etc/samba/smb.conf && '
                f'service smb restart; '
                f'service nmb restart; '
                f'systemctl enable smb.service; '
                f'systemctl enable nmb.service'
            )
        else:
            logging.info("Установка samba без конфига")
            run_command_by_root(
                f'dnf makecache && '
                f'dnf in -y samba && '
                f'mkdir -p /home/share && '
                f'chmod 777 /home/share && '
                f'service smb restart; '
                f'service nmb restart; '
                f'systemctl enable smb.service; '
                f'systemctl enable nmb.service'
            )
        with open(f'/home/{user}/Рабочий стол/share.desktop', 'w') as file_link_2:
            file_link_2.write(network_share_for_teacher)
        with open(f'{config_path}/share.desktop', 'w') as file_link:
            file_link.write(network_share.format(teacher_host=this_host))
        for host in self.host_list:
            if test_ssh(host):
                if check_student_on_host(host):
                    run_command(
                        f"sshpass -p {host.student_pass} scp {config_path}/share.desktop "
                        f"{host.student_login}@{host.hostname}:'/home/{host.student_login}/Рабочий\ стол'"
                    )
                    # ssh = paramiko.SSHClient()
                    # ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                    # ssh.load_system_host_keys()
                    # try:
                    #     ssh.connect(hostname=host.hostname, port=22, timeout=5, username=host.admin_login,
                    #                 password=host.admin_pass, allow_agent=False, look_for_keys=False)
                    #     logging.info(f"Подключено по ssh@{host.admin_login} к {host.hostname}")
                    #     channel: Channel = ssh.invoke_shell()
                    #     channel_data = str()
                    #     time.sleep(0.5)
                    #     # channel.send(f"sudo cat {config_path}/share.desktop | sudo tee /root/.ssh/authorized_keys\n")
                    #     time.sleep(0.5)
                    #     channel.send(f"{host.admin_pass}\n")
                    #     time.sleep(0.5)
                    #     channel_data += f"{str(channel.recv(99999).decode('utf-8'))}\n"
                    #     channel.close()
                    #     ssh.close()
                    #     logging.info(f"Результат работы paramiko на {host.hostname}: {channel_data}")
                    self.progress_signal.emit(
                        f"{host.hostname}: ярлык на сетевую папку скопирован"
                    )
                    success_count += 1
                    logging.info(f'{host.hostname} ярлык на сетевую папку скопирован')
                else:
                    self.progress_signal.emit(f'{host.hostname}: отсутствует {host.student_login}')
                    logging.info(f'{host.hostname} отсутствует {host.student_login}')
            else:
                self.progress_signal.emit(f'{host.hostname}: не в сети или не настроен ssh')
                logging.info(f'{host.hostname} не в сети или не настроен ssh')
        if success_count == 0:
            self.progress_signal.emit(f"\nКопирование ярлыка на сетевую папку не выполнено.")
        else:
            self.progress_signal.emit(
                f"\nКопирование ярлыка на сетевую папку завершилось.\n"
                f"Всего устройств: {hosts_count}\n"
                f"Завершено успешно: {success_count}\n"
                f"Ошибок: {hosts_count - success_count}"
            )


class VeyonSetup(QThread):
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal()

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.hosts = None
        self.host_list = []
        self.kab = ""

    def run(self):
        self.install_veyon()

    def install_veyon(self):
        """
        Установка и настройка veyon: скачивание пакета, создание ключей, копирование списка хостов и настройка по ssh на
        хостах
        """
        self.progress_signal.emit("Начало настройки veyon")

        self.progress_signal.emit("Проверка мак-адресов проводных сетевых плат")
        cnt = 0
        for host in self.host_list:
            if subprocess.run(['ping', '-c1', host.hostname], stdout=subprocess.PIPE).returncode != 0:
                self.progress_signal.emit(f'Компьютер {host.hostname} недоступен')
                logging.info(f'Компьютер {host.hostname} недоступен, veyon не будет установлен')
                continue
            self.hosts.set_item(
                key=host.name,
                hostname=host.hostname,
                mac_address=get_mac_address(host),
                admin_login=host.admin_login,
                admin_pass=host.admin_pass,
                student_login=host.student_login,
                student_pass=host.student_pass,
                setup=host.setup
            )
            cnt += 1
        self.progress_signal.emit(f"Мак-адреса проверены.\nУспешно: {cnt} из {len(self.host_list)} компьютеров")

        self.progress_signal.emit("Установка veyon на компьютере учителя...")
        logging.info(f'Установка вейон на компьютере учителя')
        is_kab_exists = run_command('veyon-cli newtorkobjects list').split('\n')
        if f'Место "{self.kab}"' in is_kab_exists:
            dlg = QMessageBox(self)
            dlg.setWindowTitle("Внимание!")
            dlg.setText(f"Кабинет {self.kab} уже есть в конфигурации Veyon. Удалить его?\n"
                        f"Ответ НЕТ добавит компьютеры в существующий кабинет.")
            dlg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            dlg.setIcon(QMessageBox.Question)
            button = dlg.exec()

            if button == QMessageBox.Yes:
                run_command_by_root(f"veyon-cli networkobjects clear; "
                                    f"veyon-cli networkobjects add location {self.kab};")
                self.progress_signal.emit(f"Кабинет {self.kab} удалён")
                logging.info(f"Кабинет {self.kab} удалён")

        network_objects = ''
        for host in self.host_list:
            mac_address = "aa:bb:cc:dd:ee:ff" if not host.mac_address else host.mac_address
            name = host.name.replace(' ', '_')
            network_objects += f'veyon-cli networkobjects add ' \
                               f'computer "{name}" "{host.hostname}" "{mac_address}" "{self.kab}"; '
        run_command_by_root(
            f"dnf --refresh -y up ; dnf in veyon -y ; rm -f /tmp/cks*; "
            f"veyon-cli authkeys delete {user}/private; veyon-cli authkeys delete {user}/public; "
            f"veyon-cli authkeys create {user}; veyon-cli authkeys setaccessgroup {user}/private {user}; "
            f"veyon-cli authkeys export {user}/public /tmp/cks-veyon.pam; veyon-cli config export /tmp/cks-veyon.json;"
            f"chown {user}:{user} /tmp/cks-*; "
            f"{network_objects} veyon-cli service start"
        )

        is_veyon_installed = run_command("veyon-cli networkobjects list")
        if f'Место "{self.kab}"' not in is_veyon_installed.split('\n')[0]:
            self.progress_signal.emit("Установка veyon на компьютере учителя не удалась")
            logging.info(f'Установка вейон на комьютере учителя не удалась')
            return
        # f"rm {config_path}/veyon_*.pem -f; "
        # f"veyon-cli config clear; "
        # f"veyon-cli config set Authentication/Method 1; "
        # f"veyon-cli config set Service/Autostart true; "
        # "veyon-cli config set VncServer/Plugin {39d7a07f-94db-4912-aa1a-c4df8aee3879}; "
        # f"veyon-cli authkeys delete {user}/private; "
        # f"veyon-cli authkeys delete {user}/public; "
        # f"veyon-cli authkeys create {user}; "
        # f"veyon-cli authkeys setaccessgroup {user}/private {user}; "
        # f"veyon-cli authkeys export {user}/public {config_path}/veyon_{user}_public_key.pem; "
        # f"veyon-cli networkobjects clear; "

        self.progress_signal.emit("Установка veyon на компьютере учителя завершена")
        logging.info(f'Установка вейон на комьютере учителя завершена успешно')

        logging.info(f'Установка вейон на комьютере учеников')

        self.progress_signal.emit("Создание ярлыка на рабочем столе")
        with open(f'/home/{user}/Рабочий стол/veyon.desktop', 'w') as file_link:
            file_link.write(veyon_link)
            self.progress_signal.emit("Ярлык создан")
        #
        # self.progress_signal.emit("Копирование публичного ключа")
        # for host in self.hosts.items_to_list():
        #     run_command(f"scp {config_path}/veyon_{user}_public_key.pem root@{host.hostname}:/tmp/")
        #     self.progress_signal.emit(f"{host.hostname}: ключ скопирован")
        # self.progress_signal.emit("Отправка команд на установку")

        self.progress_signal.emit("\n=====\nУстановка Veyon на компьютеры учеников\n=====")
        cnt = 0
        for host in self.host_list:
            if subprocess.run(['ping', '-c1', host.hostname], stdout=subprocess.PIPE).returncode != 0:
                self.progress_signal.emit(f'Компьютер {host.hostname} недоступен')
                logging.info(f'Компьютер {host.hostname} недоступен, veyon не будет установлен')
                continue
            if host.setup is True:
                self.progress_signal.emit(f'Установка Veyon на {host.hostname}...')
                self.progress_signal.emit(f'Начало обновления системы на {host.hostname}...')
                run_command(f'ssh root@{host.hostname} "dnf --refresh -y up && dnf in -y veyon-core"')
                is_veyon_installed = run_command(f'rpm -q veyon-core').startswith('veyon-core')
                if not is_veyon_installed:
                    self.progress_signal.emit(f'На {host.hostname} установка veyon не удалась по неизвестной причине.')
                    logging.info(f'На {host.hostname} установка veyon не удалась по неизвестной причине.')
                    continue
                self.progress_signal.emit(f'На {host.hostname} установлен veyon-core. Копирование ключей...')
                run_command(f'scp /tmp/cks-veyon.pam root@{host.hostname}:/tmp/')
                run_command(f'scp /tmp/cks-veyon.json root@{host.hostname}:/tmp/')
                self.progress_signal.emit(f'Ключи скопированы. Настройка {host.hostname}...')
                run_command(f'ssh root@{host.hostname} "veyon-cli authkeys delete {user}/public"')
                run_command(f'ssh root@{host.hostname} "veyon-cli authkeys import {user}/public /tmp/cks-veyon.pam"')
                run_command(f'ssh root@{host.hostname} "veyon-cli config import /tmp/cks-veyon.json"')
                run_command(f'ssh root@{host.hostname} reboot')
                # run_command(f'ssh root@{host.hostname} "rm -f /tmp/cks-veyon.json /tmp/cks-veyon.pam"')
                # run_command(f'rm -f /tmp/cks-veyon.json /tmp/cks-veyon.pam')
                logging.info(f"Veyon установлен и настроен на {host.hostname}")
                self.progress_signal.emit(f"Veyon установлен и настроен на {host.hostname}")
                cnt += 1
            else:
                self.progress_signal.emit(f'На {host.name} не настроены ключи ssh')
                logging.info(f'На {host.name} не настроены ключи ssh')
        self.progress_signal.emit(f'Установка Veyon завершена.\nУспешно: {cnt} из {len(self.host_list)} компьютеров')
        logging.info('Завершение установки Veyon')


class WorkerSignals(QObject):
    signal = pyqtSignal(str)


class SSHCommandInThreads(QRunnable):
    def __init__(self, host: Host, command):
        super().__init__()
        self.progress_signal = WorkerSignals()
        self.host = host
        self.command = command

    def run(self) -> None:
        if type(self.command) is str:
            self.run_command_on_ssh_from_str()
        elif type(self.command) is list:
            self.run_command_on_ssh_from_list(self.command)

    def run_command_on_ssh_from_str(self):
        logging.info(f"Выполнение команды {self.command} на {self.host.hostname}")
        client = SSHClient()
        client.load_system_host_keys()
        try:
            client.connect(hostname=self.host.hostname, username=self.host.admin_login, timeout=2)
            stdin, stdout, stderr = client.exec_command(self.command)
            result = stdout.read().decode().strip()
            self.progress_signal.signal.emit(f"\nРезультат выполнения на {self.host.hostname}:\n{result}")
            logging.info(f"\nРезультат выполнения на {self.host.hostname}:\n\n{result}")
        except (AuthenticationException, SSHException, socket.gaierror):
            self.progress_signal.signal.emit(f'Не удалось подключиться ssh {self.host.admin_login}@{self.host.hostname}')
            logging.info(f"\nНе удалось подключиться по ssh без пароля к {self.host.admin_login}@{self.host.hostname}")
        except Exception as e:
            self.progress_signal.signal.emit(f'{self.host.hostname} неизвестная ошибка.')
            logging.info(f"неизвестная ошибка {self.host.hostname}: {e}")
        finally:
            client.close()

    def run_command_on_ssh_from_list(self, commands_list: list):
        logging.info(f"Выполнение команды {commands_list} на {self.host.hostname}")
        client = SSHClient()
        client.load_system_host_keys()
        try:
            client.connect(hostname=self.host.hostname, username=self.host.admin_login, timeout=2)
            for command in commands_list:
                stdin, stdout, stderr = client.exec_command(command)
                result = stdout.read().decode().strip()
                self.progress_signal.signal.emit(
                    f"\nРезультат выполнения {command} на {self.host.hostname}:\n\n{result}"
                )
                logging.info(
                    f"\nРезультат выполнения {command} на {self.host.hostname}:\n\n{result}"
                )
        except (AuthenticationException, SSHException, socket.gaierror):
            self.progress_signal.signal.emit(f'\nНе удалось подключиться ssh {self.host.admin_login}@{self.host.hostname}')
            logging.info(f"Не удалось подключиться по ssh без пароля к {self.host.admin_login}@{self.host.hostname}")
        except Exception as e:
            self.progress_signal.signal.emit(f'\n{self.host.hostname} неизвестная ошибка.')
            logging.info(f"неизвестная ошибка {self.host.hostname}: {e}")
        finally:
            client.close()


class UpdateList(QThread):
    progress_signal = pyqtSignal(list)
    hosts = None

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.continue_run = True

    def run(self):
        while self.continue_run:
            hosts = Hosts()
            if self.hosts.to_list() != hosts.to_list():
                self.progress_signal.emit(hosts.to_list())
                self.hosts = Hosts()
            time.sleep(1)

    def isFinished(self):
        self.continue_run = False


class GetWorks(QThread):
    start_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.hosts_list = None
        self.date = None
        self.text = None
        self.hosts = Hosts()

    def run(self):
        hosts_count = len(self.hosts_list)
        success_count = 0
        if len(self.hosts_list) == 0:
            self.progress_signal.emit("Не выбрано ни одного компьютера")
            return
        self.start_signal.emit(
            f"Выбрано компьютеров: {hosts_count}\nСбор работ начинается\n"
        )
        for host in self.hosts.items_to_list():
            if test_ssh(host):
                if check_student_on_host(host) and host.hostname in self.hosts_list:
                    remote_desktop = run_command(f'ssh root@{host.hostname} ls "/home/{host.student_login}/Рабочий\ стол"')
                    if 'Сдать работы' not in remote_desktop.split('\n'):
                        self.progress_signal.emit(f'На рабочем столе ученика {host.hostname} нет папки Сдать работы')
                        logging.info(f'На рабочем столе ученика {host.hostname} нет папки Сдать работы')
                        continue
                    run_command(
                        f'mkdir -p "/home/{user}/Рабочий стол/Работы/"' + self.date + '/' + self.text + '/' + host.hostname
                    )
                    works_folder = f'install -d -m 0755 -o {host.student_login} -g {host.student_login} \\"/home/{host.student_login}/Рабочий стол/Сдать работы\\"'

                    run_command(
                        f'ssh root@{host.hostname} \'{works_folder}\' && '
                        f'scp -r root@{host.hostname}:\'/home/{host.student_login}/Рабочий\ стол/Сдать\ работы/*\' '
                        f'\"/home/{user}/Рабочий стол/Работы/\"{self.date}/{self.text}/{host.hostname}'
                    )

                    self.progress_signal.emit(f'{host.hostname}: работы сохранены успешно')
                    logging.info(f'{host.hostname} работы сохранены успешно')
                    success_count += 1
                elif host.hostname in self.hosts_list:
                    self.progress_signal.emit(f'{host.hostname}: отсутствует учётная запись {host.student_login}')
                    logging.info(f'{host.hostname} отсутствует {host.student_login}')
            else:
                self.progress_signal.emit(f'{host.hostname}: не в сети или не настроен ssh')
                logging.info(f'{host.hostname} не в сети или не настроен ssh')
        if success_count == 0:
            self.finish_signal.emit(f"\nСбор работ не выполнен.")
        else:
            self.finish_signal.emit(
                f"\nСбор работ завершился.\n"
                f"Было выбрано: {hosts_count}\n"
                f"Завершено успешно: {success_count}\n"
                f"Ошибок: {hosts_count - success_count}"
            )


class CleanWorks(QThread):
    start_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.hosts_list = None
        self.hosts = Hosts()

    def run(self):
        hosts_count = len(self.hosts_list)
        success_count = 0
        self.start_signal.emit(
            f"Выбрано компьютеров: {hosts_count}\nОчистка директорий для сбора работ начинается\n"
        )
        for host in self.hosts.items_to_list():
            if test_ssh(host):
                if check_student_on_host(host) and host.hostname in self.hosts_list:
                    remote_desktop = run_command(
                        f'ssh root@{host.hostname} ls "/home/{host.student_login}/Рабочий\ стол"')
                    if 'Сдать работы' not in remote_desktop.split('\n'):
                        self.progress_signal.emit(f'На рабочем столе ученика {host.hostname} нет папки Сдать работы')
                        logging.info(f'На рабочем столе ученика {host.hostname} нет папки Сдать работы')
                        continue
                    run_command(
                        f'ssh root@{host.hostname} \'rm -rf /home/{host.student_login}/Рабочий\ стол/Сдать\ работы/*\'')
                    self.progress_signal.emit(f'{host.hostname}: очистка завершена')
                    logging.info(f'{host.hostname} очистка завершена')
                    success_count += 1
                elif host.hostname in self.hosts_list:
                    self.progress_signal.emit(f'{host.hostname}: отсутствует {host.student_login}')
                    logging.info(f'{host.hostname} отсутствует {host.student_login}')
            else:
                self.progress_signal.emit(f'{host.hostname}: не в сети или не настроен ssh')
                logging.info(f'{host.hostname} не в сети или не настроен ssh')
        if success_count == 0:
            self.finish_signal.emit(f"\nОчистка директорий для сбора работ не выполнена.")
        else:
            self.finish_signal.emit(
                f"\nОчистка директорий для сбора работ завершилась.\n"
                f"Было выбрано: {hosts_count}\n"
                f"Завершено успешно: {success_count}\n"
                f"Ошибок: {hosts_count - success_count}"
            )


class RecreateStudent(QThread):
    start_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.hosts_list = None
        # self.student_pass = None
        self.hosts = Hosts()

    def run(self):
        hosts_count = len(self.hosts_list)
        success_count = 0
        self.start_signal.emit(
            f"Выбрано компьютеров: {hosts_count}\nПересоздание учётной записи ученика начинается\n"
        )
        for host in self.hosts.items_to_list():
            if test_ssh(host) and host.hostname in self.hosts_list:
                works_folder = f'install -d -m 0755 -o {host.student_login} -g {host.student_login} \\"/home/{host.student_login}/Рабочий стол/Сдать работы\\"'

                command = f'echo \'' \
                          f'pkill -u {host.student_login}; ' \
                          f'sleep 2; ' \
                          f'userdel -rf {host.student_login}; ' \
                          f'useradd {host.student_login} && ' \
                          f'chpasswd <<<\'{host.student_login}:{host.student_pass}\' && ' \
                          f'{works_folder} && reboot\' | at now'
                if check_student_on_host(host):
                    run_command(f'ssh root@{host.hostname} \"{command}\"')
                    self.progress_signal.emit(f'{host.hostname}: {host.student_login} удален и создан заново')
                    logging.info(f'{host.hostname} {host.student_login} удален и создан заново')
                    success_count += 1
                else:
                    run_command(f'ssh root@{host.hostname} \"{command}\"')
                    self.progress_signal.emit(f'{host.hostname}: {host.student_login} создан')
                    logging.info(f'{host.hostname} {host.student_login} создан')
                    success_count += 1
            elif host.hostname in self.hosts_list:
                self.progress_signal.emit(f'{host.hostname}: не в сети или не настроен ssh')
                logging.info(f'{host.hostname} не в сети или не настроен ssh')
        if success_count == 0:
            self.finish_signal.emit(f"\nПересоздание {host.student_login} не выполнено.")
        else:
            self.finish_signal.emit(
                f"\nПересоздание {host.student_login} завершилось.\n"
                f"Было выбрано: {hosts_count}\n"
                f"Завершено успешно: {success_count}\n"
                f"Ошибок: {hosts_count - success_count}"
            )


# class DeleteStudent(QThread):
#     start_signal = pyqtSignal(str)
#     progress_signal = pyqtSignal(str)
#     finish_signal = pyqtSignal(str)
#
#     def __init__(self, parent=None):
#         QThread.__init__(self, parent)
#         self.hosts_list = None
#         self.student_pass = None
#
#     def run(self):
#         hosts_count = len(self.hosts_list)
#         success_count = 0
#         self.start_signal.emit(
#             f"Выбрано компьютеров: {hosts_count}\nУдаление student начинается\n"
#         )
#         for host in self.hosts_list:
#             if test_ssh(host):
#                 if check_student_on_host(host):
#                     command = f'echo \'pkill -u student; sleep 2; userdel -rf student\' | at now'
#                     run_command(f'ssh root@{host} \"{command}\"')
#                     self.progress_signal.emit(f'{host}: student удален')
#                     logging.info(f'{host} student удален')
#                     success_count += 1
#                 else:
#                     self.progress_signal.emit(f'{host}: отсутствует student')
#                     logging.info(f'{host} отсутствует student')
#             else:
#                 self.progress_signal.emit(f'{host}: не в сети или не настроен ssh')
#                 logging.info(f'{host} не в сети или не настроен ssh')
#         if success_count == 0:
#             self.finish_signal.emit(f"\nУдаление student не выполнено.")
#         else:
#             self.finish_signal.emit(
#                 f"\nУдаление student завершилось.\n"
#                 f"Было выбрано: {hosts_count}\n"
#                 f"Завершено успешно: {success_count}\n"
#                 f"Ошибок: {hosts_count - success_count}"
#             )


class OpenSFTP(QThread):
    start_signal = pyqtSignal(str)
    progress_signal = pyqtSignal(str)
    finish_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.hosts_list = None
        self.hosts = Hosts()

    def run(self):
        hosts_count = len(self.hosts_list)
        success_count = 0
        self.start_signal.emit(
            f"Выбрано компьютеров: {hosts_count}\nДиректории открываются\n"
        )
        # sftp_adresses = ["xdg-open"]
        for host in self.hosts.items_to_list():
            if test_ssh(host) and host.hostname in self.hosts_list:
                # sftp_adresses.append(f'"sftp://root@{host}:/home/"')
                # sftp_adresses.append(f'sftp://root@{host}:/home/')
                self.progress_signal.emit(f'{host.hostname}: открыт проводник')
                logging.info(f'{host.hostname} открыт sftp')
                success_count += 1
                run_command_in_konsole(f'dolphin $HOME/Рабочий\ стол sh://{host.student_login}@{host.hostname}:/home')
                # run_command_in_xterm(f'dolphin --new-window sftp://root@{host}:/home')
            else:
                self.progress_signal.emit(f'{host.hostname}: не в сети или не настроен ssh')
                logging.info(f'{host.hostname} не в сети или не настроен ssh')
        # command = " ".join(sftp_adresses)
        if success_count == 0:
            self.finish_signal.emit(f"\nОткрытие директорий не выполнено.")
        else:
            self.finish_signal.emit(
                f"\nОткрытие директорий завершилось.\n"
            )
